using System.Collections.Generic;
using System.Net;
using System.Reflection;
using ENode.Configurations;
using ENode.EQueue;
using ENode.Eventing;
using ENode.Messaging;
using EQueue.Configurations;
using EQueue.Clients.Consumers;
using EQueue.Clients.Producers;
using ENodeMicro.Common;
using EQueue.Protocols;
using ENode.Commanding;

namespace ENodeMicro.CommandHost
{
    public static class ENodeExtensions
    {
        private static CommandService _commandService;
        private static CommandConsumer _commandConsumer;
        private static DomainEventPublisher _domainEventPublisher;
        private static DomainEventConsumer _eventConsumer;
        private static ApplicationMessagePublisher _applicationMessagePublisher;
        private static ApplicationMessageConsumer _applicationMessageConsumer;

        public static ENodeConfiguration BuildContainer(this ENodeConfiguration enodeConfiguration)
        {
            enodeConfiguration.GetCommonConfiguration().BuildContainer();
            return enodeConfiguration;
        }
        public static ENodeConfiguration UseEQueue(this ENodeConfiguration enodeConfiguration)
        {
            var assemblies = new[] { Assembly.GetExecutingAssembly() };
            enodeConfiguration.RegisterTopicProviders(assemblies);

            var configuration = enodeConfiguration.GetCommonConfiguration();
            configuration.RegisterEQueueComponents();

            _commandService = new CommandService();
            configuration.SetDefault<ICommandService, CommandService>(_commandService);

            _domainEventPublisher = new DomainEventPublisher();
            configuration.SetDefault<IMessagePublisher<DomainEventStreamMessage>, DomainEventPublisher>(_domainEventPublisher);

            _applicationMessagePublisher = new ApplicationMessagePublisher();
            configuration.SetDefault<IMessagePublisher<IApplicationMessage>, ApplicationMessagePublisher>(_applicationMessagePublisher);

            return enodeConfiguration;
        }
        public static ENodeConfiguration StartEQueue(this ENodeConfiguration enodeConfiguration)
        {
            var nameServerEndpoint = new IPEndPoint(IPAddress.Loopback, ConfigSettings.NameServerPort);
            var nameServerEndpoints = new List<IPEndPoint> { nameServerEndpoint };

            #region Producer
            _commandService.InitializeEQueue(null, new ProducerSetting
            {
                NameServerList = nameServerEndpoints
            });

            _domainEventPublisher.InitializeEQueue(new ProducerSetting
            {
                NameServerList = nameServerEndpoints
            });

            _applicationMessagePublisher.InitializeEQueue(new ProducerSetting
            {
                NameServerList = nameServerEndpoints
            });
            #endregion

            #region Consumer
            var consumerSetting = new ConsumerSetting
            {
                NameServerList = nameServerEndpoints,
                ConsumeFromWhere = ConsumeFromWhere.FirstOffset
            };
            // Command
            _commandConsumer = new CommandConsumer()
                .InitializeEQueue("ManagerCommandConsumerHostGroup", setting: consumerSetting);
            _commandConsumer
                .Subscribe("ManagerCommandTopic");

            // Domain event
            _eventConsumer = new DomainEventConsumer()
                .InitializeEQueue("ManagerEventConsumerHostGroup", setting: consumerSetting);
            _eventConsumer
                .Subscribe("ManagerEventTopic");

            // Application message
            _applicationMessageConsumer = new ApplicationMessageConsumer()
                .InitializeEQueue("ManagerMessageConsumerGroup", consumerSetting);
            _applicationMessageConsumer
                .Subscribe("MemberApplicationMessageTopic");

            #endregion

            _commandService.Start();
            _eventConsumer.Start();
            _commandConsumer.Start();
            _applicationMessageConsumer.Start();

            _domainEventPublisher.Start();
            _applicationMessagePublisher.Start();

            return enodeConfiguration;
        }
        public static ENodeConfiguration ShutdownEQueue(this ENodeConfiguration enodeConfiguration)
        {
            _eventConsumer.Shutdown();
            _commandConsumer.Shutdown();
            _domainEventPublisher.Shutdown();
            _applicationMessagePublisher.Shutdown();
            _applicationMessageConsumer.Shutdown();
            _commandService.Shutdown();
            return enodeConfiguration;
        }
    }
}